package cc.laop.support.filter;

import cc.laop.service.RedisService;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * Created by Pengpeng on 2017/5/27.
 */

@Component
@Aspect
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class RequestLimitHandler {

    private static final Logger logger = LoggerFactory.getLogger(RequestLimitHandler.class);

    @Autowired
    private RedisService redisService;


    @Before("within(@org.springframework.stereotype.Controller *) && @annotation(RequestLimit)")
    public void requestLimit(JoinPoint joinPoint) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
                .getRequest();
        RequestLimit requestLimit = (RequestLimit) joinPoint.getSignature()
                .getDeclaringType().getAnnotation(RequestLimit.class);
        if (request != null) {
            String ip = getIpAddr(request);
            String url = request.getRequestURL().toString();
            if (StringUtils.isNotEmpty(ip) && requestLimit.ipLimit() > 0) {
                String key = "ip_limit_" + ip;
                long count = redisService.getRedisTemplate().opsForValue().increment(key, 1);
                if (count == 1) {
                    redisService.getRedisTemplate().expire(key, requestLimit.ipTime(), requestLimit.unit());
                }
                if (count > requestLimit.ipLimit()) {
                    throw new RequestLimitException("IP access too often!");
                }
            }
            if (StringUtils.isNotEmpty(url) && requestLimit.urlLimit() > 0) {
                String key = "url_limit_" + url;
                long count = redisService.getRedisTemplate().opsForValue().increment(key, 1);
                if (count == 1) {
                    redisService.getRedisTemplate().expire(key, requestLimit.urlTime(), requestLimit.unit());
                }
                if (count > requestLimit.urlLimit()) {
                    throw new RequestLimitException("Url access too often!");
                }
            }
        } else {
            logger.warn("Request not found!");
        }
    }


    private String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("X-real-ip");//先从nginx自定义配置获取
        if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("x-forwarded-for");
        }
        if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

}
